package com.rain.builder;

import com.rain.bean.FieldInfo;
import com.rain.bean.TableInfo;
import com.rain.utils.Constants;
import com.rain.utils.StringUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class BuildMapperXml {

    private static final Logger logger = LoggerFactory.getLogger(BuildMapperXml.class);
    private static final String BASE_COLUMN_LIST = "base_column_list";
    private static final String BASE_QUERY_CONDITION = "base_query_condition";
    private static final String BASE_QUERY_CONDITION_EXTEND = "base_query_condition_extend";
    private static final String QUERY_CONDITION = "query_condition";


    public static void execute(TableInfo tableInfo) throws IOException {
        File folder = new File(Constants.PACKAGE_MAPPER_XML_PATH);
        if(!folder.exists()){
            folder.mkdirs();
        }

        String className = tableInfo.getBeanName()+"Mapper";
        File file = new File(folder, className + ".xml");

        try{
            file.createNewFile();
        }catch(IOException e){
            e.printStackTrace();
        }

        OutputStream outputStream = null;
        OutputStreamWriter outputStreamWriter = null;
        BufferedWriter bufferedWriter = null;

        try {
            outputStream = new FileOutputStream(file);
            outputStreamWriter = new OutputStreamWriter(outputStream, "UTF-8");
            bufferedWriter = new BufferedWriter(outputStreamWriter);

            bufferedWriter.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
                    "<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">");
            bufferedWriter.newLine();
            bufferedWriter.write("<mapper namespace=\""+ Constants.PACKAGE_MAPPER + "." + className +"\">");
            bufferedWriter.newLine();
            bufferedWriter.newLine();


            // 实体类映射
            bufferedWriter.write("\t<!--实体映射-->\n");
            String poClass = Constants.PACKAGE_ENTITY + "." + tableInfo.getBeanName();
            bufferedWriter.write("\t<resultMap id=\"base_result_map\" type=\"" + poClass + "\">\n");
            FieldInfo idField = null;
            Map<String, List<FieldInfo>> keyIndexMap = tableInfo.getKeyIndexMap();
            for (Map.Entry<String, List<FieldInfo>> entry: keyIndexMap.entrySet()) {
                if("PRIMARY".equals(entry.getKey())){
                    List<FieldInfo> fieldInfoList = entry.getValue();
                    if (fieldInfoList.size() == 1){
                        idField = fieldInfoList.get(0);
                        break;
                    }
                }
            }
            for (FieldInfo fieldInfo: tableInfo.getFieldList()) {
                bufferedWriter.write("\t\t<!--" + fieldInfo.getComment() + "-->\n");
                String key = null;
                if(idField != null && fieldInfo.getPropertyName().equals(idField.getPropertyName())){
                    key = "id";
                }else {
                    key = "result";
                }
                bufferedWriter.write("\t\t<" + key + " column=\"" + fieldInfo.getFieldName() + "\" property=\"" + fieldInfo.getPropertyName() + "\" />\n");
            }
            bufferedWriter.write("\t</resultMap>\n");
            bufferedWriter.newLine();
            bufferedWriter.newLine();

            // 通用查询列
            bufferedWriter.write("\t<!--通用查询结果-->\n");
            bufferedWriter.write("\t<sql id=\"" + BASE_COLUMN_LIST + "\">\n");
            StringBuilder columnBuilder = new StringBuilder();
            for (FieldInfo fieldInfo: tableInfo.getFieldList()) {
                columnBuilder.append(fieldInfo.getFieldName()).append(',');
            }
            String columnBuilderStr = columnBuilder.substring(0,columnBuilder.lastIndexOf(","));
            bufferedWriter.write("\t\t" + columnBuilderStr + "\n");
            bufferedWriter.write("\t</sql>\n\n");

            // 基础查询条件
            bufferedWriter.write("\t<!--基础查询条件-->\n");
            bufferedWriter.write("\t<sql id=\"" + BASE_QUERY_CONDITION + "\">\n");
            for (FieldInfo fieldInfo: tableInfo.getFieldList()) {
                String strQuery = "";
                if(ArrayUtils.contains(Constants.SQL_STAING_TYPE,fieldInfo.getSqlType())){
                    strQuery = " and query." + fieldInfo.getPropertyName() + " != ''";
                }
                bufferedWriter.write("\t\t<if test=\"query."+ fieldInfo.getPropertyName() +" != null" + strQuery + "\">\n");
                bufferedWriter.write("\t\t\tand " + fieldInfo.getFieldName() + " = #{query." + fieldInfo.getPropertyName() + "}\n");
                bufferedWriter.write("\t\t</if>\n\n");

            }
            bufferedWriter.write("\t</sql>\n\n");

            // 扩展的查询条件
            bufferedWriter.write("\t<!--扩展的查询条件-->\n");
            bufferedWriter.write("\t<sql id=\"" + BASE_QUERY_CONDITION_EXTEND + "\">\n");
            for (FieldInfo fieldInfo: tableInfo.getFieldExtendList()) {
                String andWhere = "";
                if(ArrayUtils.contains(Constants.SQL_STAING_TYPE,fieldInfo.getSqlType())){
                    andWhere = "and " + fieldInfo.getFieldName() + " like concat('%', #{query." + fieldInfo.getPropertyName() + "}, '%')";
                }else if(ArrayUtils.contains(Constants.SQL_DATE_TIME_TYPES,fieldInfo.getSqlType()) ||
                        ArrayUtils.contains(Constants.SQL_DATE_TYPES,fieldInfo.getSqlType())) {
                    if(fieldInfo.getPropertyName().endsWith(Constants.QUERY_TIME_START)) {
                        andWhere = "<![CDATA[ and " + fieldInfo.getFieldName() + " >= str_to_date(#{query." + fieldInfo.getPropertyName() + "}, '%Y-%m-%d') ]]>";
                    }else if(fieldInfo.getPropertyName().endsWith(Constants.QUERY_TIME_END)) {
                        // date_sub 减去间隔 减去-1天
                        andWhere = "<![CDATA[ and " + fieldInfo.getFieldName() + " < date_sub(str_to_date(#{query." + fieldInfo.getPropertyName() + "}, '%Y-%m-%d'), interval -1 day) ]]>";
                    }
                }
                bufferedWriter.write("\t\t<if test=\"query."+ fieldInfo.getPropertyName() +" != null" + " and query." + fieldInfo.getPropertyName() + " != ''" + "\">\n");
                bufferedWriter.write("\t\t\t" + andWhere + "\n");
                bufferedWriter.write("\t\t</if>\n\n");

            }
            bufferedWriter.write("\t</sql>\n\n");

            // 通用查询条件
            bufferedWriter.write("\t<!--通用查询条件-->\n");
            bufferedWriter.write("\t<sql id=\"" + QUERY_CONDITION + "\">\n");
            bufferedWriter.write("\t\t<where>\n");
            bufferedWriter.write("\t\t\t<include refid=\"" + BASE_QUERY_CONDITION + "\"/>\n");
            bufferedWriter.write("\t\t\t<include refid=\"" + BASE_QUERY_CONDITION_EXTEND + "\"/>\n");
            bufferedWriter.write("\t\t</where>\n");
            bufferedWriter.write("\t</sql>\n\n");

            // 查询列表
            bufferedWriter.write("\t<!--查询列表-->\n");
            bufferedWriter.write("\t<select id=\"" + "selectList" + "\" resultMap=\"base_result_map\" >\n");
            bufferedWriter.write("\t\tSELECT <include refid=\"" + BASE_COLUMN_LIST +"\"/> FROM " + tableInfo.getTableName() + " <include refid=\"" + QUERY_CONDITION + "\"/>\n");
            bufferedWriter.write("\t\t<if test=\"query.orderBy!=null\">order by ${query.orderBy}</if>\n");
            bufferedWriter.write("\t\t<if test=\"query.simplePage!=null\">limit #{query.simplePage.start},#{query.simplePage.pageSize}</if>\n");
            bufferedWriter.write("\t</select>\n\n");

            // 查询数量
            bufferedWriter.write("\t<!--查询数量-->\n");
            bufferedWriter.write("\t<select id=\"" + "selectCount" + "\" resultType=\"java.lang.Long\" >\n");
            bufferedWriter.write("\t\tSELECT count(1) FROM " + tableInfo.getTableName() +"\n");
            bufferedWriter.write("\t\t<include refid=\"" + QUERY_CONDITION + "\"/>\n");
            bufferedWriter.write("\t</select>\n\n");

            // 单挑插入
            bufferedWriter.write("\t<!--单条插入(匹配有值字段)-->\n");
            bufferedWriter.write("\t<insert id=\"" + "insert" + "\" parameterType=\"" + poClass + "\" >\n");
            FieldInfo autoIncrementField = null;
            for (FieldInfo fieldInfo: tableInfo.getFieldList()) {
                if(fieldInfo.getAutoIncrement() != null && fieldInfo.getAutoIncrement()) {
                    autoIncrementField = fieldInfo;
                    break;
                }
            }
            if(autoIncrementField != null) {
                bufferedWriter.write("\t\t<selectKey keyProperty=\"bean." + autoIncrementField.getFieldName() + "\"  resultType=\"" + autoIncrementField.getJavaType() + "\" order=\"AFTER\">\n");
                bufferedWriter.write("\t\t\tSELECT LAST_INSERT_ID()\n");
                bufferedWriter.write("\t\t</selectKey>\n");
            }
            bufferedWriter.write("\t\tINSERT INTO " + tableInfo.getTableName() + "\n");
            bufferedWriter.write("\t\t<trim prefix=\"(\" suffix=\")\" suffixOverrides=\",\">\n");
            for (FieldInfo fieldInfo : tableInfo.getFieldList()) {
                bufferedWriter.write("\t\t\t<if test=\"bean." + fieldInfo.getPropertyName() + " != null\">\n");
                bufferedWriter.write("\t\t\t\t" + fieldInfo.getFieldName() + ",\n");
                bufferedWriter.write("\t\t\t</if>\n");
            }
            bufferedWriter.write("\t\t</trim>\n");
            bufferedWriter.write("\t\tVALUES\n");
            bufferedWriter.write("\t\t<trim prefix=\"(\" suffix=\")\" suffixOverrides=\",\">\n");
            for (FieldInfo fieldInfo : tableInfo.getFieldList()) {
                bufferedWriter.write("\t\t\t<if test=\"bean." + fieldInfo.getPropertyName() + " != null\">\n");
                bufferedWriter.write("\t\t\t\t#{bean." + fieldInfo.getPropertyName() + "},\n");
                bufferedWriter.write("\t\t\t</if>\n");
            }
            bufferedWriter.write("\t\t</trim>\n");
            bufferedWriter.write("\t</insert>\n\n");

            // 插入或更新
            bufferedWriter.write("\t<!--插入或更新(匹配有值字段) 如果没有主键没有索引会一直插入-->\n");
            bufferedWriter.write("\t<insert id=\"" + "insertOrUpdate" + "\" parameterType=\"" + poClass + "\" >\n");
            bufferedWriter.write("\t\tINSERT INTO " + tableInfo.getTableName() + "\n");
            bufferedWriter.write("\t\t<trim prefix=\"(\" suffix=\")\" suffixOverrides=\",\">\n");
            for (FieldInfo fieldInfo : tableInfo.getFieldList()) {
                bufferedWriter.write("\t\t\t<if test=\"bean." + fieldInfo.getPropertyName() + " != null\">\n");
                bufferedWriter.write("\t\t\t\t" + fieldInfo.getFieldName() + ",\n");
                bufferedWriter.write("\t\t\t</if>\n");
            }
            bufferedWriter.write("\t\t</trim>\n");
            bufferedWriter.write("\t\tVALUES\n");
            bufferedWriter.write("\t\t<trim prefix=\"(\" suffix=\")\" suffixOverrides=\",\">\n");
            for (FieldInfo fieldInfo : tableInfo.getFieldList()) {
                bufferedWriter.write("\t\t\t<if test=\"bean." + fieldInfo.getPropertyName() + " != null\">\n");
                bufferedWriter.write("\t\t\t\t#{bean." + fieldInfo.getPropertyName() + "},\n");
                bufferedWriter.write("\t\t\t</if>\n");
            }
            bufferedWriter.write("\t\t</trim>\n");
            bufferedWriter.write("\t\ton DUPLICATE key update\n");

            Map<String, String> keyTempMap = new HashMap<>();
            for (Map.Entry<String,List<FieldInfo>> entry : keyIndexMap.entrySet()){
                List<FieldInfo> fieldInfoList = entry.getValue();
                for (FieldInfo fieldInfo: fieldInfoList) {
                    keyTempMap.put(fieldInfo.getFieldName(), fieldInfo.getFieldName());
                }
            }
            bufferedWriter.write("\t\t<trim suffixOverrides=\",\">\n");
            for (FieldInfo fieldInfo : tableInfo.getFieldList()) {
                if(keyTempMap.get(fieldInfo.getFieldName()) != null) {
                    continue;
                }
                bufferedWriter.write("\t\t\t<if test=\"bean." + fieldInfo.getPropertyName() + " != null\">\n");
                bufferedWriter.write("\t\t\t\t" + fieldInfo.getFieldName() + " = " + "VALUES(" + fieldInfo.getFieldName() + "),\n");
                bufferedWriter.write("\t\t\t</if>\n");
            }
            bufferedWriter.write("\t\t</trim>\n");
            bufferedWriter.write("\t</insert>\n\n");

            // 批量插入
            bufferedWriter.write("\t<!--批量插入-->\n");
            bufferedWriter.write("\t<insert id=\"" + "insertBatch" + "\" parameterType=\"" + poClass + "\">\n");
            StringBuilder stringBuilder = new StringBuilder();
            for (FieldInfo fieldInfo:tableInfo.getFieldList()) {
                if(fieldInfo.getAutoIncrement()){
                    continue;
                }
                stringBuilder.append(fieldInfo.getFieldName()).append(',');
            }
            String insertFieldBufferStr = stringBuilder.substring(0,stringBuilder.lastIndexOf(","));
            bufferedWriter.write("\tINSERT INTO " + tableInfo.getTableName() + " (" + insertFieldBufferStr + ") VALUES\n");
            bufferedWriter.write("\t\t<foreach collection=\"list\" item=\"item\" separator=\",\">\n");
            bufferedWriter.write("\t\t\t(\n");
            StringBuilder stringBuilderProperty = new StringBuilder();
            for (FieldInfo fieldInfo:tableInfo.getFieldList()) {
                if(fieldInfo.getAutoIncrement()){
                    continue;
                }
                stringBuilderProperty.append("#{item." + fieldInfo.getPropertyName() + "}").append(',');
            }
            String insertPropertyBufferStr = stringBuilderProperty.substring(0,stringBuilderProperty.lastIndexOf(","));
            bufferedWriter.write("\t\t\t\t" + insertPropertyBufferStr + "\n");
            bufferedWriter.write("\t\t\t)\n");
            bufferedWriter.write("\t\t</foreach>\n");
            bufferedWriter.write("\t</insert>\n\n");

            // 批量插入或更新
            bufferedWriter.write("\t<!--批量插入或更新-->\n");
            bufferedWriter.write("\t<insert id=\"" + "insertOrUpdateBatch" + "\" parameterType=\"" + poClass + "\">\n");
            StringBuilder stringBuilderInsertUpdate = new StringBuilder();
            for (FieldInfo fieldInfo:tableInfo.getFieldList()) {
                if(fieldInfo.getAutoIncrement()){
                    continue;
                }
                stringBuilderInsertUpdate.append(fieldInfo.getFieldName()).append(',');
            }
            String insertUpdateFieldBufferStr = stringBuilderInsertUpdate.substring(0,stringBuilderInsertUpdate.lastIndexOf(","));
            bufferedWriter.write("\tINSERT INTO " + tableInfo.getTableName() + " (" + insertUpdateFieldBufferStr + ") VALUES\n");
            bufferedWriter.write("\t\t<foreach collection=\"list\" item=\"item\" separator=\",\">\n");
            bufferedWriter.write("\t\t\t(\n");
            StringBuilder stringBuilderPropertyInsertUpdate = new StringBuilder();
            for (FieldInfo fieldInfo:tableInfo.getFieldList()) {
                if(fieldInfo.getAutoIncrement()){
                    continue;
                }
                stringBuilderPropertyInsertUpdate.append("#{item." + fieldInfo.getPropertyName() + "}").append(',');
            }
            String insertUpdatePropertyBufferStr = stringBuilderPropertyInsertUpdate.substring(0,stringBuilderPropertyInsertUpdate.lastIndexOf(","));
            bufferedWriter.write("\t\t\t\t" + insertUpdatePropertyBufferStr + "\n");
            bufferedWriter.write("\t\t\t)\n");
            bufferedWriter.write("\t\t</foreach>\n");
            bufferedWriter.write("\t\ton DUPLICATE key update\n");
            StringBuilder stringBuilder1 = new StringBuilder();
            for (FieldInfo fieldInfo:tableInfo.getFieldList()) {
                if(fieldInfo.getAutoIncrement()){
                    continue;
                }
                stringBuilder1.append("\t\t" + fieldInfo.getFieldName() + " = " +  "VALUES(" + fieldInfo.getFieldName() +  ")" +  ",\n");
            }
            bufferedWriter.write(stringBuilder1.substring(0,stringBuilder1.lastIndexOf(",")) + "\n");
            bufferedWriter.write("\t</insert>\n\n");

            Map<String, List<FieldInfo>>  keyIndexMapName = tableInfo.getKeyIndexMap();
            for (Map.Entry<String,List<FieldInfo>> entry: keyIndexMapName.entrySet()) {
                List<FieldInfo> value = entry.getValue();
                Integer index = 0;
                StringBuffer stringBufferName = new StringBuffer();
                StringBuilder stringBuilderParam = new StringBuilder();
                for (FieldInfo fieldInfo : value) {
                    index++;
                    stringBufferName.append(StringUtils.uperCaseFirstLetter(fieldInfo.getPropertyName()));
                    stringBuilderParam.append(fieldInfo.getFieldName() + "=#{" + fieldInfo.getPropertyName() +  "}");
                    if (index < value.size()) {
                        stringBufferName.append("And");
                        stringBuilderParam.append(" and ");
                    }
                }

                // 根据ID修改
                bufferedWriter.write("\t<!--根据" + stringBufferName + "修改-->\n");
                bufferedWriter.write("\t<update id=\"" + "updateBy" + stringBufferName + "\" parameterType=\"" + poClass + "\" >\n");
                bufferedWriter.write("\t\tUPDATE " + tableInfo.getTableName() + " \n");
                bufferedWriter.write("\t\t<set>\n");
                for (FieldInfo fieldInfo : tableInfo.getFieldList()) {
                    if(keyTempMap.get(fieldInfo.getFieldName()) != null) {
                        continue;
                    }
                    bufferedWriter.write("\t\t\t<if test=\"bean." + fieldInfo.getPropertyName() + " != null\">\n");
                    bufferedWriter.write("\t\t\t\t" + fieldInfo.getFieldName() + " = " + "#{bean." + fieldInfo.getPropertyName() + "},\n");
                    bufferedWriter.write("\t\t\t</if>\n");
                }
                bufferedWriter.write("\t\t</set>\n");
                bufferedWriter.write("\t\twhere " + stringBuilderParam +  " \n");
                bufferedWriter.write("\t</update>\n\n");

                // 根据ID查询
                bufferedWriter.write("\t<!--根据" + stringBufferName + "查询-->\n");
                bufferedWriter.write("\t<select id=\"" + "selectBy" + stringBufferName + "\" resultMap=\"" + "base_result_map" + "\">\n");
                bufferedWriter.write("\t\tselect <include refid=\"" + BASE_COLUMN_LIST + "\"/> from " + tableInfo.getTableName() + " where " + stringBuilderParam +  "\n");
                bufferedWriter.write("\t</select>\n");

                // 根据ID删除
                bufferedWriter.write("\t<!--根据" + stringBufferName + "删除-->\n");
                bufferedWriter.write("\t<delete id=\"" + "deleteBy" + stringBufferName + "\">\n");
                bufferedWriter.write("\t\tdelete from " + tableInfo.getTableName() + " where " + stringBuilderParam +  "\n");
                bufferedWriter.write("\t</delete>\n");
            }
            bufferedWriter.write("</mapper>");
            bufferedWriter.newLine();
            bufferedWriter.flush();
        }catch (Exception e){
            logger.info("创建mapperXML失败", e.getMessage());
            e.printStackTrace();
        }finally {
            if(bufferedWriter != null) {
                bufferedWriter.close();
            }
            if(outputStreamWriter != null) {
                outputStreamWriter.close();
            }
            if(outputStream != null) {
                outputStream.close();
            }
        }


    }
}
